// #include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <linenoise.h>

#include "cli.h"

static int usage(void);


Command_t* command_list = NULL;
static Argument_t *CUR_ARG = NULL;



// 创建参数定义
// Argument_t* create_arument(
//     const char *name,
//     const char *description,
//     ArgType type,
//     int requirted
// ) {
//     Argument_t *arg = (Argument_t*)malloc(sizeof(Argument_t));
//     arg->name = name;
//     arg->descripute = strdup(description);
//     arg->type = type;
//     arg->options = NULL;
//     arg->option_count = 0;
//     arg->required = requirted;
//     arg->next = NULL;
//     return arg;
// }

// // 为枚举参数添加选项
// void add_enum_options(Argument_t *arg, char ** options, int count) {
//     if (arg->type != ARG_ENUM) 
//         return;
//     arg->options = (char **)malloc(sizeof(char *) * count);
//     arg->option_count = count;
//     for (int i = 0; i < count; i++) {
//         arg->options[i] = strdup(options[1]);
//     }
// }


// 查找子命令
SubCommand_t* find_subcmd(Command_t *cmd, char *name) {
    SubCommand_t *current = cmd->subcommands;

    while (current != NULL) {
        if (strcmp(current->name, name) == 0) {
            return current;
        }
    }

    return NULL;
}

// 查找命令中的参数
Argument_t* find_arg(Command_t *cmd, char *name) {
    Argument_t *current = cmd->args;
    printf("cmd name %s\n", current->name);

    while (current != NULL) {
        if (strcmp(current->name, name) == 0) {
            return current;
        }
        current = current->next;
    }

    return NULL;
}

// 添加子命令
void add_subcmd_to_cmd(Command_t *cmd, SubCommand_t *new_subcmd) {
    if (find_subcmd(cmd, new_subcmd->name) != NULL) {
        printf("%s 命令中已存在子命令 %s\n", cmd->name, new_subcmd->name);
    }

    if (cmd->subcommands == NULL) {
        cmd->subcommands = new_subcmd;
    } else {
        SubCommand_t *current = cmd->subcommands;
        while (current != NULL) {
            current = current->next;
        }
        current->next = new_subcmd;
    }
}


// 添加参数到子命令
void add_subcmd_argument(Command_t *cmd, char *name, Argument_t *arg) {
    SubCommand_t* cur_subcmd = find_subcmd(cmd, name);
    if (cur_subcmd != NULL) {
        if (cur_subcmd->args == NULL) {
            cur_subcmd->args = arg;
        } else {
            Argument_t *cur_arg = cur_subcmd->args;
            while (cur_arg->next != NULL) {
                if (strcmp(cur_arg->name, arg->name) == 0) {
                    printf("%s 子命令 %s 已经存在参数 %s\n",cmd->name, name, arg->name);
                    return;
                }
                cur_arg = cur_arg->next;
            }
            cur_arg->next = arg;
        }
    } else {
        printf("命令 %s 添加子命令 %s 失败\n", cmd->name, name);
    }
}


// 添加参数到命令
void add_command_argment(Command_t *cmd, Argument_t *arg) {
    if (cmd->args == NULL) {
        cmd->args = arg;
    } else {
        Argument_t *current = cmd->args;
        while (current->next != NULL) {
            if (strcmp(current->name, arg->name) == 0) {
                printf("命令 %s 已存在参数 %s\n", cmd->name, arg->name);
                return;
            }
            current = current->next;
        }
        current->next = arg;
    }
}


int register_command (Command_t* new_cmd) {
    if (new_cmd == NULL || new_cmd->name == NULL || new_cmd->handler == NULL) {
        fprintf(stderr, "错误: 无效的命令参数\n");
        return -1;
    }

    // 检查命令是否存在
    Command_t *existing_cmd  = command_list;
    while (existing_cmd  != NULL) {
        if(strcmp(existing_cmd->name, new_cmd->name) == 0) {
            fprintf(stderr, "错误: 命令 '%s' 已存在\n", new_cmd->name);
            return -1;
        }
        existing_cmd = existing_cmd->next;
    }

    // 添加新命令
    Command_t *cmd_entry = (Command_t*)malloc(sizeof(Command_t));
    if (cmd_entry == NULL) {
        fprintf(stderr, "错误: 内存分配失败\n");
        return -1;
    }

    cmd_entry->name = strdup(new_cmd->name);
    cmd_entry->description = new_cmd->description ? strdup(new_cmd->description) : NULL; 
    cmd_entry->usage = new_cmd->usage ? strdup(new_cmd->usage) : NULL;
    cmd_entry->handler = new_cmd->handler;
    cmd_entry->args = NULL;
    cmd_entry->subcommands = NULL;
    cmd_entry->next = command_list;  // 插入到链表头部
    
    // 复制参数列表
    Argument_t *src_arg = new_cmd->args;
    Argument_t *last_arg = NULL;
    while (src_arg != NULL) {
        Argument_t *new_arg = (Argument_t *)malloc(sizeof(Argument_t));
        printf("arg name %s\n", src_arg->name);
        new_arg->name = strdup(src_arg->name);
        new_arg->descripute = strdup(src_arg->descripute);
        new_arg->usage = strdup(src_arg->usage);
        new_arg->required = src_arg->required;
        new_arg->next = NULL;

        // 添加参数链表
        if (last_arg == NULL) {
            cmd_entry->args = new_arg;
        } else {
            last_arg->next = new_arg;
        }

        last_arg = new_arg;
        src_arg = src_arg->next;
    }
    
    // 更新链表头
    command_list = cmd_entry;
    
    printf("注册命令: %s\n", new_cmd->name);
    return 0;
}

Command_t* find_command(char *name) {
    Command_t* current = command_list;

    while(current != NULL) {
        if (strcmp(current->name, name) == 0) {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

// // 生成参数提示信息
// char* generate_arg_hint(Command_t *cmd, char *arg_name) {
//     static char hint[512];
//     hint[0] = '\0';

//     Argument_t *arg = find_arg(cmd, arg_name);

//     if (arg != NULL) {
//         const char *required_str = arg->required ? "必选" : "可选";
//         snprintf(hint, sizeof(hint), "参数%s: %s (%s)", arg->name, arg->descripute, required_str);
//     } else {
//         snprintf(hint, sizeof(hint), "额外参数");
//     }

//     return hint;
// }

char* hint_callback (const char *buf, int *color, int *bold) {
    static char hint[512] = {0};
    hint[0] = '\0';

    *color = 35;
    *bold = 0;

    if (strlen(buf) == 0) {
        return NULL;
    }

    // 分割命令行参数
    char *tokens[10] = {0};
    int token_count = 0;

    char* buf_copy = strdup(buf);    // 动态分配内存并复制字符串
    char* token = strtok(buf_copy, " ");

    while (token != NULL && token_count < 10) {
        tokens[token_count] = token;
        token_count ++; 
        token = strtok(NULL, " ");
    } 

    if (token_count == 1) {
        // 只输入了命令
        Command_t* cmd = find_command(tokens[0]);
        if (cmd != NULL) {
            snprintf(hint, sizeof(hint), "  %s", cmd->description);
            if (cmd->args != NULL) {
                strcat(hint, "参数：");
                Argument_t *arg = cmd->args;
                while (arg != NULL) {
                    strcat(hint, arg->required ? "<" : "[");
                    strcat(hint, arg->name);
                    strcat(hint, arg->required ? ">" : "]");
                    if (arg->next != NULL)
                        strcat(hint, " ");
                    
                    arg = arg->next;
                }
            }
        }
    } else if (token_count > 1) {
        // 输入命令和参数
        Command_t *cmd = find_command(tokens[0]);
        if (cmd != NULL) {
            const char *patial_arg = tokens[token_count-1];
            Argument_t *arg = cmd->args;

            // 找到对应的参数
            for (int i = 0;  arg != NULL; i++) {
                if (strcmp(arg->name, patial_arg) == 0) {   // 完全输入第一个参数之后才会有提示
                    strcat(hint, arg->descripute);
                    break;
                }
                arg = arg->next;
            }
            if (arg == NULL) {      // 如果没有匹配到或者是参数命令输入补全不进行补全
                return NULL;
            }
        }
    }

    free(buf_copy);
    return hint[0] ? hint : NULL;
}


// void complete_argument(Argument_t *arg, const char *partial, linenoiseCompletions *lc) {
//     if (strlen(partial) == 0 || 
//         strncmp(arg->name, partial, strlen(partial)) == 0) {
//         linenoiseAddCompletion(lc, arg->name);
//     }
// }

void completion_callback (const char *buf, linenoiseCompletions *lc) {
    char *tokens[20] = {0};
    int token_count = 0;

    char *buf_copy = strdup(buf);
    char *token = strtok(buf_copy, " ");

    while (token != NULL && token_count < 20) {
        tokens[token_count] = token;
        token_count ++;
        token = strtok(NULL, " ");
    } 

    if (token_count == 0) {
        // 空输入，补全所有命令
        Command_t *current = command_list;
        while (current != NULL) {
            linenoiseAddCompletion(lc, current->name);
            current = current->next;
        }
    } else if (token_count == 1) {
        // 输入部分命令，补全匹配的命令
        const char *partial_cmd = tokens[0];
        Command_t *current = command_list;
       
        while (current != NULL) {
            if (strncmp(current->name, partial_cmd, strlen(partial_cmd)) == 0) {
                linenoiseAddCompletion(lc, current->name); 
            } 
            current = current->next;
        }
    } else if (token_count == 2) {
        // 命令补全完毕，进行参数补全
        Command_t *cmd = find_command(tokens[0]);
        if (cmd != NULL) {
            const char *patial_arg = tokens[token_count-1];
            Argument_t *arg = cmd->args;

            // 找到对应的参数
            while (arg != NULL) {
                if (strncmp(arg->name, patial_arg, strlen(patial_arg)) == 0) {
                    // 重建前缀（除了最后一个token）
                    char prefix[256] = {0};
                    for (int i = 0; i < token_count - 1; i++) {
                        if (i > 0) strcat(prefix, " ");
                        strcat(prefix, tokens[i]);
                    }
                    if (token_count > 1) {
                        strcat(prefix, " ");
                    }
                
                    strcat(prefix, arg->name);
                    linenoiseAddCompletion(lc, prefix);
                }
                arg = arg->next;
            }
        }
    }

    free(buf_copy);
}

static int args_split(char *cmd, int len, char *argv[10])
{
  char *ptr;
  int position, argc, i;

  ptr = cmd;
  position = argc = 0;

  while (position < len) {
    /* strip bank and tab */
    while ((*ptr == ' ' || *ptr == '\t') && position < len) {
      *ptr = '\0';
      ptr ++;
      position ++;
    }

    if (argc >= 10) {
      printf("Too many args\n");
      break;
    }

    if (position >= len) break;

    if (*ptr == '"') {
      ptr ++;
      position ++;
      argv[argc] = ptr;
      argc ++;

      /* skip this string */
      while (*ptr != '"' && position < len) {
          if (*ptr == '\\') {
              if (*(ptr + 1) == '"') {
                  ptr ++;
                  position ++;
              }
          }
          ptr ++;
          position ++;
      }
      if (position >= len) break;

      /* skip '"' */
      *ptr = '\0';
      ptr ++;
      position ++;
    } else {
      argv[argc] = ptr;
      argc ++;
      while ((*ptr != ' ' && *ptr != '\t') && position < len) {
          ptr ++;
          position ++;
      }
      if (position >= len) break;
    }
  }
  return argc;
}


int execute_command(char *line) {
    if (strlen(line) == 0) {
        return 1;
    }

    char *argv[20] = {0};
    int argc = 0;

    argc = args_split(line, strlen(line), argv);
    
    if (argc > 0) {
        Command_t *cmd = find_command(argv[0]);
        if (strcmp(argv[0], "clear") == 0) {
            linenoiseClearScreen();
        } else if (strcmp(argv[0], "exit") == 0) {
           exit(0);
        } else if (strcmp(argv[0], "help") == 0) {
            usage();
        } else if (cmd != NULL) {
            cmd->handler(argc, argv);
        } else {
            printf("未知命令： %s\n", argv[0]);
            printf("\n");
            usage();
        }
    }
}

void free_args(Command_t *cmd) {
    Argument_t *cur_arg = cmd->args;

    while (cur_arg != NULL) {
        Argument_t *next = cur_arg->next;
        free(cur_arg->name);
        free(cur_arg->descripute);
        free(cur_arg->usage);
        cur_arg = next;
    }
    cmd->args = NULL;
}

void free_commands() {
    Command_t *current = command_list;
    while (current != NULL) {
        Command_t *next = current->next;
        free(current->name);
        free(current->description);
        free(current->usage);
        free_args(current);
        free(current);
        current = next;
    }
    command_list = NULL;
}

static int usage(void)
{
    Command_t *current = command_list;
    while (current != NULL) {
        printf("%-10s %-5s \n", current->name, current->usage);

        Argument_t *cur_arg = current->args;
        while (cur_arg != NULL) {
            printf("    %-10s %-5s \n", cur_arg->name, cur_arg->usage);
            cur_arg = cur_arg->next;
        }
        current = current->next;
    }
    
    return 0;
}

void initalize_linenoise(void) {
    linenoiseSetCompletionCallback(completion_callback);
    linenoiseSetHintsCallback(hint_callback);
    linenoiseSetMultiLine(1);
    linenoiseHistorySetMaxLen(100);
    linenoiseHistoryLoad(HISTORY_PATH);
}
